#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

Mat src, dst, map_x, map_y, gray_src;
const char* OUTPUT = "remap demo";
int indexs;
void update_map(void);

int main() {
  src = imread("../images/2.jpg");
  if (src.empty()) {
    cout << "could not load image.." << endl;
    return -1;
  }
  namedWindow("opencv setup demo", CV_WINDOW_AUTOSIZE);
  imshow("opencv setup demo", src);

  map_x.create(src.size(), CV_32FC1);
  map_y.create(src.size(), CV_32FC1);
  int c = 0;
  while (true) {
    c = waitKey(500);
    if (static_cast<uint16_t>(c) == 27) {
      break;
    }
    indexs = c % 4;
    update_map();
    remap(src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT,
          Scalar(0, 255, 255));
    imshow(OUTPUT, dst);
  }
  return 0;
}

void update_map(void) {
  for (int row = 0; row < src.rows; row++) {
    for (int col = 0; col < src.cols; col++) {
      switch (indexs) {
        case 0:
          if (col > (src.cols * 0.25) && col <= (src.cols * 0.75) &&
              row > (src.rows * 0.25) && row <= (src.rows * 0.75)) {
            map_x.at<float>(row, col) = 2 * (col - (src.cols * 0.25) + 0.5);
            map_y.at<float>(row, col) = 2 * (row - (src.rows * 0.25) + 0.5);
          } else {
            map_x.at<float>(row, col) = 0;
            map_y.at<float>(row, col) = 0;
          }
          break;
        case 1:
          map_x.at<float>(row, col) = src.cols - col - 1;
          map_y.at<float>(row, col) = row;
          break;
        case 2:
          map_x.at<float>(row, col) = col;
          map_y.at<float>(row, col) = src.rows - row - 1;
          break;
        case 3:
          map_x.at<float>(row, col) = src.cols - col - 1;
          map_y.at<float>(row, col) = src.rows - row - 1;
          break;
      }
    }
  }
}